package com.silence.gmall.util;

import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.ParseException;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.util.Timeout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.Objects;

/**
 * HTTP客户端工具类
 * 提供常用的HTTP请求功能，包括GET、POST请求和文件下载
 * 
 * @author Silence
 * @version 1.0
 * @since 1.0
 */
public class HttpClientUtil {

    private static final Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);

    /**
     * 默认连接超时时间（毫秒）
     */
    private static final int DEFAULT_CONNECT_TIMEOUT = 10000;

    /**
     * 默认读取超时时间（毫秒）
     */
    private static final int DEFAULT_READ_TIMEOUT = 30000;

    /**
     * 默认字符编码
     */
    private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;

    /**
     * 私有构造器，防止实例化工具类
     */
    private HttpClientUtil() {
        throw new UnsupportedOperationException("工具类不支持实例化");
    }

    /**
     * 执行HTTP GET请求
     *
     * @param url 请求URL，不能为null或空字符串
     * @return 响应内容字符串，请求失败时返回null
     * @throws IllegalArgumentException 如果url为null或空字符串
     */
    public static String doGet(String url) {
        return doGet(url, null);
    }

    /**
     * 执行HTTP GET请求，支持自定义请求头
     *
     * @param url     请求URL，不能为null或空字符串
     * @param headers 请求头参数，可以为null
     * @return 响应内容字符串，请求失败时返回null
     * @throws IllegalArgumentException 如果url为null或空字符串
     */
    public static String doGet(String url, Map<String, String> headers) {
        validateUrl(url);

        RequestConfig config = createRequestConfig();

        try (CloseableHttpClient httpClient = HttpClients.custom()
                .setDefaultRequestConfig(config)
                .build()) {

            HttpGet httpGet = new HttpGet(url);
            
            // 设置请求头
            if (headers != null) {
                headers.forEach(httpGet::setHeader);
            }

            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                return handleResponse(response);
            }

        } catch (IOException e) {
            logger.error("执行GET请求失败，URL: {}", url, e);
            return null;
        }
    }

    /**
     * 执行HTTP POST请求
     *
     * @param url     请求URL，不能为null或空字符串
     * @param jsonBody JSON格式的请求体，可以为null
     * @return 响应内容字符串，请求失败时返回null
     * @throws IllegalArgumentException 如果url为null或空字符串
     */
    public static String doPost(String url, String jsonBody) {
        return doPost(url, jsonBody, null);
    }

    /**
     * 执行HTTP POST请求，支持自定义请求头
     *
     * @param url     请求URL，不能为null或空字符串
     * @param jsonBody JSON格式的请求体，可以为null
     * @param headers 请求头参数，可以为null
     * @return 响应内容字符串，请求失败时返回null
     * @throws IllegalArgumentException 如果url为null或空字符串
     */
    public static String doPost(String url, String jsonBody, Map<String, String> headers) {
        validateUrl(url);

        RequestConfig config = createRequestConfig();

        try (CloseableHttpClient httpClient = HttpClients.custom()
                .setDefaultRequestConfig(config)
                .build()) {

            HttpPost httpPost = new HttpPost(url);
            
            // 设置请求头
            if (headers != null) {
                headers.forEach(httpPost::setHeader);
            }

            // 设置请求体
            if (jsonBody != null && !jsonBody.trim().isEmpty()) {
                StringEntity entity = new StringEntity(jsonBody, ContentType.APPLICATION_JSON);
                httpPost.setEntity(entity);
            }

            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                return handleResponse(response);
            }

        } catch (IOException e) {
            logger.error("执行POST请求失败，URL: {}", url, e);
            return null;
        }
    }

    /**
     * 下载文件到指定路径
     *
     * @param url      文件下载URL，不能为null或空字符串
     * @param filePath 保存文件的完整路径，不能为null或空字符串
     * @return true：下载成功，false：下载失败
     * @throws IllegalArgumentException 如果参数为null或空字符串
     */
    public static boolean downloadFile(String url, String filePath) {
        return downloadFile(url, filePath, null);
    }

    /**
     * 下载文件到指定路径，支持自定义请求头
     *
     * @param url      文件下载URL，不能为null或空字符串
     * @param filePath 保存文件的完整路径，不能为null或空字符串
     * @param headers  请求头参数，可以为null
     * @return true：下载成功，false：下载失败
     * @throws IllegalArgumentException 如果参数为null或空字符串
     */
    public static boolean downloadFile(String url, String filePath, Map<String, String> headers) {
        validateUrl(url);
        validateFilePath(filePath);

        RequestConfig config = createRequestConfig();

        try (CloseableHttpClient httpClient = HttpClients.custom()
                .setDefaultRequestConfig(config)
                .build()) {

            HttpGet httpGet = new HttpGet(url);
            
            // 设置请求头
            if (headers != null) {
                headers.forEach(httpGet::setHeader);
            }

            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                if (response.getCode() == HttpStatus.SC_OK) {
                    HttpEntity entity = response.getEntity();
                    if (entity != null) {
                        return saveToFile(entity, filePath);
                    }
                } else {
                    logger.warn("下载文件失败，HTTP状态码: {}, URL: {}", response.getCode(), url);
                }
            }

        } catch (IOException e) {
            logger.error("下载文件失败，URL: {}, 文件路径: {}", url, filePath, e);
        }

        return false;
    }

    /**
     * 创建请求配置
     *
     * @return RequestConfig对象
     */
    private static RequestConfig createRequestConfig() {
        return RequestConfig.custom()
                .setConnectTimeout(Timeout.ofMilliseconds(DEFAULT_CONNECT_TIMEOUT))
                .setResponseTimeout(Timeout.ofMilliseconds(DEFAULT_READ_TIMEOUT))
                .build();
    }

    /**
     * 处理HTTP响应
     *
     * @param response HTTP响应对象
     * @return 响应内容字符串，解析失败时返回null
     */
    private static String handleResponse(CloseableHttpResponse response) {
        if (response.getCode() == HttpStatus.SC_OK) {
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                try {
                    String result = EntityUtils.toString(entity, DEFAULT_CHARSET);
                    EntityUtils.consume(entity);
                    return result;
                } catch (IOException e) {
                    logger.error("读取响应内容失败", e);
                } catch (ParseException e) {
                    logger.error("解析响应内容失败", e);
                }
            }
        } else {
            logger.warn("HTTP请求失败，状态码: {}", response.getCode());
        }
        return null;
    }

    /**
     * 保存HTTP响应实体到文件
     *
     * @param entity   HTTP响应实体
     * @param filePath 文件保存路径
     * @return true：保存成功，false：保存失败
     */
    private static boolean saveToFile(HttpEntity entity, String filePath) {
        try {
            // 确保目录存在
            Path path = Paths.get(filePath);
            Path parentDir = path.getParent();
            if (parentDir != null && !Files.exists(parentDir)) {
                Files.createDirectories(parentDir);
            }

            // 写入文件
            byte[] bytes = EntityUtils.toByteArray(entity);
            try (BufferedOutputStream outputStream = new BufferedOutputStream(
                    new FileOutputStream(filePath))) {
                outputStream.write(bytes);
                outputStream.flush();
            }

            EntityUtils.consume(entity);
            logger.info("文件下载成功，保存路径: {}", filePath);
            return true;

        } catch (IOException e) {
            logger.error("保存文件失败，文件路径: {}", filePath, e);
            return false;
        }
    }

    /**
     * 验证URL参数
     *
     * @param url URL字符串
     * @throws IllegalArgumentException 如果URL为null或空字符串
     */
    private static void validateUrl(String url) {
        Objects.requireNonNull(url, "URL不能为null");
        if (url.trim().isEmpty()) {
            throw new IllegalArgumentException("URL不能为空字符串");
        }
    }

    /**
     * 验证文件路径参数
     *
     * @param filePath 文件路径字符串
     * @throws IllegalArgumentException 如果文件路径为null或空字符串
     */
    private static void validateFilePath(String filePath) {
        Objects.requireNonNull(filePath, "文件路径不能为null");
        if (filePath.trim().isEmpty()) {
            throw new IllegalArgumentException("文件路径不能为空字符串");
        }
    }
}
